import threading, time, sys, subprocess 
if(sys.platform == "win32"):
    import wexpect
else:
    import pexpect
from support.utils.toolkit import Log

class Shell:
    WHITE_LIST = ["ls", "uname", "whoami", "pwd"]
    def executeP(cmd, *, workdir='.', timeout=0, wait=True, contentMaxLength=100):
        def killProcess():
            process.terminate()
        if(timeout):
            timer = threading.Timer(timeout, killProcess)
            timer.start()
        Log.d(cmd)
        process = subprocess.run(cmd.split(), cwd=workdir)
        if(not wait): return None
        returnCode = process.poll()
        content = ""
        while returnCode is None:
            if(len(content) < contentMaxLength):content += process.stdout.readline()
            if(timeout and timer.is_alive() and len(content)):timer.cancel()
            returnCode =process.poll()
        for line in process.stdout:
            if(len(content) < contentMaxLength):content += line
        if(timeout and timer.is_alive()):timer.cancel()
        return {"returncode":returnCode, "content":content, "cmd":cmd}

    def execute(cmd, *, timeout=-1, policies=None, realtime=None):
        expect=[]
        content=None
        returncode=0
        Log.d("execute : {} | expect: {}".format(cmd, policies))
        if(sys.platform == "win32"):
            process = wexpect.spawn(cmd)
            expect.append(wexpect.EOF)
            expect.append(wexpect.TIMEOUT)
        else:
            process = pexpect.spawn(cmd)
            expect.append(pexpect.EOF)
            expect.append(pexpect.TIMEOUT)
        if(policies):
            returncode = 1
            if(timeout <= 0):timeout = 10
            expect.extend([policy[0] for policy in policies])
            content=[None for policy in policies]
        else:
            timeout = None
        cpl = process.compile_pattern_list(expect)
        while(True):
            index = process.expect_list(cpl, timeout=timeout)
            if(index > 1):
                returncode = 0
                data = process.match.group(0)
                if(sys.platform == "linux"):data = data.decode()
                if(realtime):realtime(data)
                content[index - 2] = data
                policy = policies[index - 2]
                if(len(policy) > 1 and policy[1]):
                    process.sendline(policy[1])
                else:
                    process.close
            else:
                if(not policies and index == 0):returncode=0
                if(realtime):realtime(process.before)
                break
        Log.d("cmd:{} retcode:{}".format(cmd, returncode))
        return {"returncode":returncode, "cmd":cmd, "content":content}
